package model

import (
	"admin/contrib/validator"
	"bytes"
	"common/helper"
	"encoding/json"
	"errors"
	"fmt"
	"github.com/valyala/fasthttp"
	"github.com/valyala/fastjson"
	"io/ioutil"
	"net/http"
	"strconv"
	"strings"
	"time"
)

type thirdEpay struct {
}
type EpayCallBack struct {
	MchId      int    `json:"mch_id"`
	Code       int    `json:"code"`
	OrderNo    string `json:"order_no"`
	DisOrderNo string `json:"dis_order_no"`
	OrderPrice int    `json:"order_price"`
	RealPrice  int    `json:"real_price"`
	OrderCost  int    `json:"order_cost"`
	NtiTime    int    `json:"nti_time"`
	Sign       string `json:"sign"`
}

type EpayWithdrawCallBack struct {
	OrderNo    string `json:"order_no"`
	MchOrderNo string `json:"mch_order_no"`
	Amount     int    `json:"amount"`
	Status     int    `json:"status"`
	Fee        int    `json:"fee"`
	Sign       int64  `json:"sign"`
}

type withdrawResp struct {
	Code            string `json:"code"`
	Msg             string `json:"msg"`
	OrdStatus       string `json:"ordStatus"`
	MerchantOrderId string `json:"merchantOrderId"`
	Amount          string `json:"amount"`
	Time            string `json:"time"`
	Order           string `json:"order"`
	Sign            string `json:"sign"`
}

func (that *thirdEpay) DepositCallBack(fctx *fasthttp.RequestCtx) (map[string]string, error) {

	m := map[string]string{}
	params := EpayCallBack{}

	if err := helper.JsonUnmarshal(fctx.PostBody(), &params); err != nil {

		return m, errors.New("参数错误")
	}

	m["order_id"] = params.OrderNo
	m["amount"] = fmt.Sprintf(`%d`, params.OrderPrice)
	m["success_time"] = fmt.Sprintf(`%d`, params.NtiTime)
	if params.Code != 1 {
		m["state"] = fmt.Sprintf(`%d`, DepositCancelled)
	} else {
		m["state"] = fmt.Sprintf(`%d`, DepositSuccess)
	}

	return m, nil
}

func (that *thirdEpay) WithdrawCallBack(fctx *fasthttp.RequestCtx) (paymentCallbackResp, error) {

	data := paymentCallbackResp{}

	data.AppId = string(fctx.FormValue("appId"))
	data.CustId = string(fctx.FormValue("custId"))
	data.MerchantOrderId = string(fctx.FormValue("merchantOrderId"))
	data.Order = string(fctx.FormValue("order"))
	data.OrderStatus = string(fctx.FormValue("orderStatus"))
	data.Amount = string(fctx.FormValue("amount"))
	data.Sign = string(fctx.FormValue("sign"))

	query := "select * from tbl_withdraw where id='" + data.MerchantOrderId + "'"
	order := tblWithdraw{}
	err := meta.MerchantDB.Get(&order, query)
	if err != nil {
		return data, err
	}
	keyy := ""
	query = "select app_key from tbl_pay_factory where fid=" + order.FID
	err = meta.MerchantDB.Get(&keyy, query)
	if err != nil {
		return data, err
	}
	content := fmt.Sprintf(`amount=%s&appId=%s&custId=%s&merchantOrderId=%s&order=%s&orderStatus=%s&key=%s`, data.Amount, data.AppId, data.CustId, data.MerchantOrderId, data.Order, data.OrderStatus, keyy)

	helper.InfoLog("回调订单号：%s回调参数：%s", data.MerchantOrderId, content+data.Sign)
	sign := strings.ToUpper(helper.MD5Hash(content))

	if data.Sign != sign {
		fmt.Printf("old sign=%s, new state=%s", data.Sign, sign)
		helper.InfoLog("%s订单号签名不对", data.MerchantOrderId, content)
		return data, errors.New(helper.SignValidErr)
	}
	return data, nil
}

func (that *thirdEpay) Deposit(fctx *fasthttp.RequestCtx, ts time.Time, uid, amount, orderNo string, p TblPayFactory) (paymentDepositResp, error) {

	ip := helper.FromRequest(fctx)

	var (
		mid     int64
		appid   int64
		paycode int64
		iamount int64
	)
	if validator.CtypeDigit(p.Mchid) {
		mid, _ = strconv.ParseInt(p.Mchid, 10, 64)
	}
	if validator.CtypeDigit(p.AppId) {
		appid, _ = strconv.ParseInt(p.AppId, 10, 64)
	}
	if validator.CtypeDigit(p.PayCode) {
		paycode, _ = strconv.ParseInt(p.PayCode, 10, 64)
	}
	if validator.CtypeDigit(amount) {
		iamount, _ = strconv.ParseInt(amount, 10, 64)
	}

	return createEpayOrder(mid, appid, paycode, iamount*100, p.Url, p.AppKey, orderNo, ip, uid, meta.Callback+"epay", meta.WebUrl)
}

func createEpayOrder(mchid, appId, payCode, amount int64, url, appKey, orderId, ip, uid, payNoticeUrl, payJumpUrl string) (paymentDepositResp, error) {

	resp := paymentDepositResp{
		OrderID: orderId,
	}
	ts := time.Now().Unix()
	content := strings.ToUpper(fmt.Sprintf(`app_id=%d&mch_id=%d&order_no=%s&pay_code=%d&pay_jump_url=%s&pay_notice_url=%s&price=%d&time=%d&key=%s`, appId, mchid, orderId, payCode, payJumpUrl, payNoticeUrl, amount, ts, appKey))

	sign := strings.ToLower(helper.MD5Hash(content))
	recs := map[string]interface{}{
		"mch_id":         mchid,
		"pay_code":       payCode,
		"order_no":       orderId,
		"price":          amount,
		"app_id":         appId,
		"user_ip":        ip,
		"user_id":        uid,
		"pay_notice_url": payNoticeUrl,
		"pay_jump_url":   payJumpUrl,
		"time":           fmt.Sprintf(`%d`, ts),
		"sign":           sign,
	}
	requestBody, err := helper.JsonMarshal(recs)
	if err != nil {
		return resp, errors.New("参数错误")
	}

	header := map[string]string{
		"Content-Type": "application/json",
	}
	requestURI := fmt.Sprintf("%s/CreateOrder", url)

	body, statusCode, err := httpDoTimeout(requestBody, "POST", requestURI, header, time.Second*8)
	if err != nil || statusCode != 200 {
		return resp, errors.New(helper.PayServerErr)
	}

	var p fastjson.Parser
	v, err := p.ParseBytes(body)
	if err != nil {
		return resp, fmt.Errorf(helper.PayServerErr)
	}

	if v.GetInt("code") != 0 {
		return resp, fmt.Errorf(helper.PayServerErr)
	}
	d := v.Get("data")
	resp.Addr = string(d.GetStringBytes("pay_url"))
	resp.Oid = string(d.GetStringBytes("Dis_order_no"))

	return resp, nil
}

func withdrawEpayOrder(iamount float64, accountNo, uid, pixId, pixType, orderId string, pay TblPayFactory, RealName string) (withdrawResp, error) {
	//resp := paymentWithdrawResp{
	//	OrderID: orderId,
	//}
	var data withdrawResp
	var amount int64
	iamount = iamount * 100
	amount = int64(iamount)
	content := fmt.Sprintf(`amount=%d&appId=%s&backUrl=%s&cardType=%s&countryCode=%s&cpf=%s&currencyCode=%s&custId=%s&email=%s&merchantOrderId=%s&phone=%s&remark=%s&type=%s&userName=%s&walletId=%s&key=%s`, amount, pay.AppId, pay.NotifyUrl, pixType, pay.CountryCode, accountNo, pay.CurrencyCode, pay.Mchid, "email", orderId, "phone", pay.PayCode, "PIX", uid, pixId, pay.AppKey)

	helper.InfoLog("订单号%s，提交三方的参数：%s", orderId, content)
	sign := strings.ToUpper(helper.MD5Hash(content))

	requestURI := fmt.Sprintf("%s", pay.Url)

	recs := map[string]interface{}{
		"amount":          amount,
		"appId":           pay.AppId,
		"backUrl":         pay.NotifyUrl,
		"cardType":        pixType,
		"countryCode":     pay.CountryCode,
		"cpf":             accountNo,
		"currencyCode":    pay.CurrencyCode,
		"custId":          pay.Mchid,
		"email":           "email",
		"merchantOrderId": orderId,
		"phone":           "phone",
		"remark":          pay.PayCode,
		"type":            "PIX",
		"userName":        uid,
		"walletId":        pixId,
		"sign":            sign,
	}
	requestBody, err := helper.JsonMarshal(recs)
	if err != nil {
		return data, errors.New("参数错误")
	}

	client := &http.Client{}
	req, err := http.NewRequest("POST", requestURI, bytes.NewReader(requestBody))

	if err != nil {

		return data, errors.New(helper.PayServerErr)
	}
	req.Header.Add("Content-Type", "application/json")

	res, err := client.Do(req)
	fmt.Println(err)
	if err != nil {

		return data, errors.New(helper.PayServerErr)
	}
	defer res.Body.Close()

	body, err := ioutil.ReadAll(res.Body)
	helper.InfoLog("订单号%s，提交三方返回信息：%s", orderId, string(body))
	if err != nil {
		return data, errors.New(helper.PayServerErr)
	}

	err = json.Unmarshal(body, &data)
	if err != nil {
		return data, fmt.Errorf(helper.PayServerErr)
	}

	return data, nil
}

type EpayCheckBack struct {
	Code            string `json:"code"`
	Msg             string `json:"msg"`
	CustId          string `json:"custId"`
	AppId           string `json:"appId"`
	OrderStatus     string `json:"orderStatus"`
	Order           string `json:"order"`
	MerchantOrderId string `json:"merchantOrderId"`
	Amount          string `json:"amount"`
	Remark          string `json:"remark"`
	CasDate         string `json:"casDate"`
	OrdDesc         string `json:"ordDesc"`
	Sign            string `json:"sign"`
}

func withdrawCheckOrder(merchantOrderId, order string, pay TblPayFactory) (EpayCheckBack, error) {

	var data EpayCheckBack

	requestURI := fmt.Sprintf("%s", "https://api.uudapay.com/br/payoutQuery1234.json")

	content := fmt.Sprintf(`appId=%s&custId=%s&merchantOrderId=%s&key=%s`, pay.AppId, pay.Mchid, merchantOrderId, pay.AppKey)

	sign := strings.ToUpper(helper.MD5Hash(content))

	recs := map[string]string{
		"merchantOrderId": merchantOrderId,
		//"order":           "",
		"custId": pay.Mchid,
		"appId":  pay.AppId,
		"sign":   sign,
	}
	requestBody, err := helper.JsonMarshal(recs)
	fmt.Println(string(requestBody))
	if err != nil {
		return data, errors.New("参数错误")
	}

	client := &http.Client{}

	req, err := http.NewRequest("POST", requestURI, bytes.NewReader(requestBody))

	if err != nil {
		return data, errors.New(helper.PayServerErr)
	}
	req.Header.Add("Content-Type", "application/json")

	res, err := client.Do(req)
	fmt.Println(err)
	if err != nil {

		return data, errors.New(helper.PayServerErr)
	}
	defer res.Body.Close()

	body, err := ioutil.ReadAll(res.Body)
	helper.InfoLog("订单号%s，审核三方返回信息：%s", merchantOrderId, string(body))
	if err != nil {
		return data, errors.New(helper.PayServerErr)
	}

	err = json.Unmarshal(body, &data)
	if err != nil {
		return data, fmt.Errorf(helper.PayServerErr)
	}

	if data.Code == "900003" && strings.Contains(data.Msg, "Failed to query") {
		data.Code = "-1"
	}

	return data, nil
}
